//
// Controller connection
//

#ifndef _CON_CONNECTION_H_
#define _CON_CONNECTION_H_

#include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread.hpp>
#include <list>

#include "sqlhandle.h"
#include "teacup.h"

class controllers_network;
class con_command;
class controllers_network;

class con_connection
  : public boost::enable_shared_from_this<con_connection>,
    private boost::noncopyable
{
public:

    explicit con_connection(boost::asio::io_service &_io_service, controllers_network &_network, sqlhandle &_sqlhandle);
    
    ~con_connection();
    
    boost::asio::ip::tcp::socket& socket();
      
    void start();
    void stop();
    
    boost::asio::ip::address remote_address();
    
    void add_command_to_queue(con_command *_command);


    bool pult_connection_;
    unsigned int controller_id_;
    
    con_state state_;
    
    teacup encoder_;
    bool secure_connection_;
    bool need_remove_controller_;
    
    boost::asio::deadline_timer timer_;
    
    void close_connection();
    
protected:
    
    void controller_handle_read(const boost::system::error_code& error, size_t bytes_transferred);
    void controller_handle_write(const boost::system::error_code& error);
    void controller_handle_last_write(const boost::system::error_code& error);
    void controller_handle_timer(const boost::system::error_code &_error);
    void controller_handle_read_timeout(const boost::system::error_code &_error);
    
    int read_restart_count_;  
    void start_read_timeout();

    void start_new_command(con_command *_command);
    bool start_command_from_queue();
    void start_queue_command();

    void start_command();
    void start_timer();
    
    void dump_packet(bool _read, boost::asio::const_buffer _buffer, unsigned int _size = 0);

    boost::asio::ip::tcp::socket socket_;
    boost::asio::io_service::strand strand_;
    con_command *command_;

    

    enum
	{ buffer_len_ = 1024 };		// buffer for read from controller

    boost::array<char, buffer_len_> read_buffer_;
    std::vector<boost::asio::const_buffer> write_buffer_;

    controllers_network &network_;
    sqlhandle &sqlhandle_;

    typedef std::list<con_command*> command_queue_t;

    command_queue_t command_queue_;
    boost::mutex command_queue_mutex_;
    
};

typedef boost::shared_ptr<con_connection> con_connection_ptr;

#endif // _CON_CONNECTION_H_
